package com.king.juc.n8.jucdemo.semaphore;

import com.king.juc.n7.MockConnection;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * DIY简易连接池
 * 享元模式
 * 欠缺:
 * 连接的动态增长与收缩
 * 连接活性(可用性检测)
 * 等待超时处理
 * 分布式hash
 *
 * @author king
 * @date 2020/12/6 22:34
 */
@Slf4j(topic = "c.Pool")
public class Pool {

    /**
     * 连接池大小
     */
    private final int poolSize;
    /**
     * 连接对象数组
     */
    private Connection[] connections;
    /**
     * 连接状态数组 0: 空闲 1: 繁忙
     */
    private AtomicIntegerArray states;
    private Semaphore semaphore;

    public Pool(int poolSize) {
        this.poolSize = poolSize;
        // 让许可数与资源数一致
        this.semaphore = new Semaphore(poolSize);
        this.connections = new Connection[poolSize];
        this.states = new AtomicIntegerArray(new int[poolSize]);

        // 初始化链接对象
        for (int i = 0; i < poolSize; i++) {
            connections[i] = new MockConnection("连接" + (i + 1));
        }
    }

    /**
     * 借连接
     */
    public Connection borrow() {
        // 获取许可
        try {
            // 没有许可的线程， 在此等待
            semaphore.acquire();
        } catch (InterruptedException e) {
            log.error("error: ", e);
        }
        for (int i = 0; i < poolSize; i++) {
            // 获取空闲连接
            if (states.get(i) == 0 && states.compareAndSet(i, 0, 1)) {
                log.debug("获取连接{}", connections[i]);
                return connections[i];
            }
        }
        // 不会执行
        return null;
    }

    /**
     * 归还连接
     */
    public void free(Connection conn) {
        for (int i = 0; i < poolSize; i++) {
            if (connections[i] == conn) {
                log.debug("归还连接{}", connections[i]);
                states.set(i, 0);
                semaphore.release();
                break;
            }
        }
    }
}
